package com.errol.generic.file.core.service;

import com.renjia.service.generic.file.core.pojo.FileExtension;
import com.renjia.service.generic.file.core.pojo.Filepath;
import com.renjia.service.generic.file.core.pojo.TempFile;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * Created by Errol on 20/12/2017.
 * 文件服务，所有文件的起点路径为 {@code fileBasePath = ServerProperties.getInstance().getFileBasePath()}
 * 服务内文件相对路径，都是相对 {@code fileBasePath} 的路径
 * 服务出入口的地址分隔符为 / ，服务内存取文件时应转换为 File.separator
 * 服务内自动判定是否为 , 分隔的多个文件，多个文件返回 , 分隔的字符串
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2020/10/21
 * @since v4.7.6
 */
public interface FileService {

    /**
     * 将上传的文件存入 temp 文件夹，第二天凌晨 4 点删除
     *
     * @param file      待存储文件
     * @param extension 保存文件格式，可以为 null ，null 则使用原文件后缀
     * @param maxSize   文件最大大小，单位 byte
     * @return 临时文件相关信息
     * @throws IOException 异常
     */
    TempFile tempFile(@NonNull MultipartFile file, @Nullable FileExtension extension, @Nullable Long maxSize) throws IOException;

    /**
     * 是否是临时文件
     *
     * @param from 待检查文件路径
     * @return bool
     */
    boolean isTemp(@NonNull String from);

    /**
     * 由文件路径获取文件扩展类型 FileExtension
     *
     * @param filename 文件路径
     * @return 可能为 null
     */
    @Nullable
    FileExtension getFileExtension(String filename);

    /**
     * 将文件转移到新存储路径，新文件名由 {@link com.renjia.service.generic.base.service.UnifiedIdService} 生成，可以多个文件同时转移
     *
     * @param from  待转移文件相对路径
     * @param toDir 转移操作的目标文件夹
     * @return 新的文件相对路径
     * @throws IOException 异常
     */
    String transfer(@NonNull String from, @NonNull Filepath toDir) throws IOException;

    /**
     * 将文件转移到新存储路径，可以多个文件同时转移
     *
     * @param from     待转移文件相对路径
     * @param toDir    转移操作的目标文件夹
     * @param filename 新文件的文件名，需要带文件扩展名，数量需与 from 中一致
     * @return 新的文件相对路径
     * @throws IOException 异常
     */
    String transfer(@NonNull String from, @NonNull Filepath toDir, @Nullable String filename) throws IOException;

    /**
     * 将文件拷贝到新存储路径，新文件名由 {@link com.renjia.service.generic.base.service.UnifiedIdService} 生成，可以多个文件同时拷贝
     *
     * @param from  待拷贝文件相对路径
     * @param toDir 拷贝操作的目标文件夹
     * @return 新的文件相对路径
     * @throws IOException 异常
     */
    String copy(@NonNull String from, @NonNull Filepath toDir) throws IOException;

    /**
     * 将文件拷贝到新存储路径，可以多个文件同时拷贝
     *
     * @param from     待拷贝文件相对路径
     * @param toDir    拷贝操作的目标文件夹
     * @param filename 新文件的文件名，需要带文件扩展名，数量需与 from 中一致
     * @return 新的文件相对路径
     * @throws IOException 异常
     */
    String copy(@NonNull String from, @NonNull Filepath toDir, @Nullable String filename) throws IOException;

    /**
     * 删除文件，可以传入空字符串，删除操作不会处理 _th 、_iv 等缩略图
     *
     * @param from 待删除文件名
     */
    void delete(@NonNull String from);

    /**
     * 检查 from 指向的文件是否都存在
     *
     * @param from 需要检查的文件路径
     * @return 全存在返回 true
     */
    boolean allExist(@NonNull String from);

    /**
     * 获取随机文件名，包含子目录路径，不含基础目录路径
     *
     * @param filepath      文件夹
     * @param fileExtension 文件扩展
     * @return 服务端使用的文件完整路径
     */
    String newFilename(@NonNull Filepath filepath, @NonNull FileExtension fileExtension);

    /**
     * 在文件夹下创建唯一命名的文件
     *
     * @param filepath      文件路径
     * @param fileExtension 文件后缀
     * @return 对应文件
     */
    File newFile(@NonNull Filepath filepath, @NonNull FileExtension fileExtension);

    /**
     * 获取文件目录下指定文件名的文件
     *
     * @param filepath 文件目录，自动处理二级目录
     * @param filename 文件名称，需要带后缀
     * @return 对应文件
     */
    File getFile(@NonNull Filepath filepath, @NonNull String filename);

    /**
     * 获取单个文件
     *
     * @param from 文件相对路径，"" 将抛出异常
     * @return 对应文件
     */
    File getFile(@NonNull String from);

    /**
     * 获取多个文件
     *
     * @param from 文件相对路径，以 , 分隔
     * @return 对应文件 list
     */
    List<File> getFiles(@NonNull String from);

    /**
     * 将数据写入 json 文件，读取 json 文件通过 getFile 获取文件后在外层解析
     * <p>
     * 注意：此方法中 根据 Field 来转化对象
     *
     * @param data  数据
     * @param toDir json 文件所在 path
     * @return json 文件路径
     * @throws IOException
     */
    String writeToJsonFile(@NonNull Object data, @NonNull Filepath toDir) throws IOException;

    /**
     * 存储文件路径到数据库前，检查文件路径是否被编辑，支持多文件路径，执行以下步骤：
     * 对比 oldFroms 和 newFroms ，如果相同，直接返回 oldFroms
     * 先遍历 newFroms 指向的文件，如果存在，就移动到 toDir 代表的文件夹内，并生成新的文件路径作为返回值
     * 再遍历 oldFroms 指向的文件，如果存在，就删除
     *
     * @param oldFroms 数据表中已存储的文件路径
     * @param newFroms 将要存储的文件路径，
     * @param toDir    新文件保存到的 Filepath
     * @return 编辑后存储到数据库的文件路径
     * @throws IOException
     */
    String transferFilesBeforeSave(@NonNull String oldFroms, @NonNull String newFroms, @NonNull Filepath toDir) throws IOException;
}
